package cn.ztydata.teachingsystem.heaven.service;

import cn.ztydata.teachingsystem.exception.ServiceException;
import cn.ztydata.teachingsystem.heaven.cons.ExerciseType;
import cn.ztydata.teachingsystem.heaven.cons.StudentAnswerStatus;
import cn.ztydata.teachingsystem.heaven.dao.ExerciseBlankDao;
import cn.ztydata.teachingsystem.heaven.dao.ExerciseOptionDao;
import cn.ztydata.teachingsystem.heaven.entity.exercise.BlankSolution;
import cn.ztydata.teachingsystem.heaven.entity.exercise.Exercise;
import cn.ztydata.teachingsystem.heaven.entity.exercise.ExerciseBlank;
import cn.ztydata.teachingsystem.heaven.entity.exercise.ExerciseOption;
import cn.ztydata.teachingsystem.heaven.entity.test.StudentAnswer;
import cn.ztydata.teachingsystem.heaven.entity.test.TestExercise;
import cn.ztydata.teachingsystem.heaven.util.JsonUtil;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * 学生答题服务类
 * Created by cx on 2015/3/30.
 */
@Service
public class StudentAnswerService extends BaseService {
    @Autowired
    private TestService testService;

    @Autowired
    private ExerciseOptionDao exerciseOptionDao;
    @Autowired
    private ExerciseBlankDao exerciseBlankDao;

    /**
     * 评判选择题得分
     * 
     * @param testExercise 作业习题
     * @param studentAnswer 习题回答
     * 
     * @author cx
     * @since 2015/3/30
     */
    public void correctChoice(TestExercise testExercise, StudentAnswer studentAnswer) {
        //获取学生所选的选项ID集合
        List<Long> selectedOptionIds = studentAnswer.getOptions();

        if (selectedOptionIds == null || selectedOptionIds.isEmpty()) {
            log.debug("未答选择题:selectedOptionIds == null || selectedOptionIds.isEmpty()");

            //未答，0分
            studentAnswer.setCorrectResult(StudentAnswerStatus.NOT_ANSWER, 0);
            return;
        }

        //回答内容转为json字符串存储
        studentAnswer.setAnswerContent(new JsonUtil<>().convertToString(selectedOptionIds));

        //获取习题的正确选项ID
        List<Long> optionIds = exerciseOptionDao.getRightOptionIds(testExercise.getExerciseId());

        log.debug("循环选择题学生答案");
        //将学生答案一一比对标准答案，标准答案集合清空时表示答题全中
        int rightCnt = optionIds.size();
        for (long selectOptionId : selectedOptionIds) {
            if (optionIds.contains(selectOptionId)) {
                log.debug("选对答案:optionIds.contains(selectOptionId)");
                optionIds.remove(selectOptionId);
            }
        }

        if (selectedOptionIds.size() == rightCnt && optionIds.isEmpty()) {
            log.debug("答对判分");
            //正确，满分
            studentAnswer.setCorrectResult(StudentAnswerStatus.RIGHT_ANSWER, testExercise.getScore());
        }
        else {
            log.debug("答错判分");
            //错误，0分
            studentAnswer.setCorrectResult(StudentAnswerStatus.WRONG_ANSWER, 0);
        }
    }

    /**
     * 评判判断题得分
     * 
     * @param testExercise 作业习题
     * @param studentAnswer 习题回答
     *                       
     * @author cx
     * @since 2015/3/30
     */
    public void correctTrueOrFalse(TestExercise testExercise, StudentAnswer studentAnswer) {
        //获取学生所选的选项（0：错误，1：正确）
        List<Long> options = studentAnswer.getOptions();

        if (options == null || options.isEmpty()) {
            log.debug("判断题未答:options == null || options.isEmpty()");

            //未答，0分
            studentAnswer.setCorrectResult(StudentAnswerStatus.NOT_ANSWER, 0);
            return;
        }

        int option = options.get(0).intValue();

        //回答内容转为json字符串存储
        studentAnswer.setAnswerContent(String.valueOf(option));

        //直接判断答题的正确性
        if (exerciseOptionDao.isRight(testExercise.getExerciseId(), option)) {
            log.debug("答对判分");
            //正确，满分
            studentAnswer.setCorrectResult(StudentAnswerStatus.RIGHT_ANSWER, testExercise.getScore());
        }
        else {
            log.debug("答错判分");
            //错误，0分
            studentAnswer.setCorrectResult(StudentAnswerStatus.WRONG_ANSWER, 0);
        }
    }

    /**
     * 评判填空题得分
     * 
     * @param testExercise 作业习题
     * @param studentAnswer 习题回答
     *                       
     * @author cx
     * @since 2015/3/30
     */
    public void correctCompletion(TestExercise testExercise, StudentAnswer studentAnswer) {
        int answerSum = 0; //习题要求的答案总数
        int rightCount = 0; //正确答案的计数

        //获取学生的填空项答案
        List<ExerciseBlank> answerBlanks = studentAnswer.getExerciseBlanks();

        if (answerBlanks == null || answerBlanks.isEmpty()) {
            log.debug("填空题未答:answerBlanks == null || answerBlanks.isEmpty()");

            //未答，0分
            studentAnswer.setCorrectResult(StudentAnswerStatus.NOT_ANSWER, 0);
            return;
        }

        log.debug("循环填空题回答");
        for (ExerciseBlank answerBlank : answerBlanks) {
            //获取一个填空的要求答案数和备选答案文本集合
            ExerciseBlank exerciseBlank = exerciseBlankDao.getBlankWithSolutions(answerBlank.getId());

            //累加每一个空的要求答案数
            int blankAnswerCount = exerciseBlank.getAnswerCount();
            answerSum += blankAnswerCount;

            //获取备选答案的集合
            List<String> solutionTexts = exerciseBlank.getSolutionTexts();
            //获取学生的填空答案集合
            List<BlankSolution> blankSolutions = answerBlank.getSolutions();

            if (blankAnswerCount != blankSolutions.size()) {
                log.debug("填空项答案数目与要求答案不符:blankAnswerCount != blankSolutions.size()");
                log.warn("填空答案数与要求不符:blankId->{},blankAnswerCount->{},answerCount->{}", answerBlank.getId(), blankAnswerCount, blankSolutions.size());
                throw new ServiceException("填空项答案数目与要求答案不符");
            }

            log.debug("循环填空题答案");
            for (BlankSolution blankSolution : blankSolutions) {
                String textSolution = blankSolution.getTextSolution();

                if (solutionTexts.contains(textSolution)) {
                    log.debug("填空项回答正确:solutionTexts.contains(textSolution)");

                    //标记此答案为正确
                    blankSolution.setRightStatus(1);
                    //将对上的答案从备选答案集合中删除，保证下次循环的判断
                    solutionTexts.remove(textSolution);
                    //累计答对的答案数
                    rightCount++;
                }
                else {
                    log.debug("填空项回答错误");
                    //标记此答案为错误
                    blankSolution.setRightStatus(0);
                }
            }
        }

        //将填空项答案转为json字符串存储
        studentAnswer.setAnswerContent(new JsonUtil<>().convertToString(answerBlanks));

        //习题填空要求的答案总数，计算每一答案的分值
        int blankScore = testExercise.getScore() / answerSum; //在添加习题时已确保了分值是答案总数的倍数
        //习题得分
        int score = blankScore * rightCount;

        //正确答案的总数不等于习题的要求答案总数，标识该习题回答错误
        if (rightCount != answerSum) {
            log.debug("答错判分");
            //错误
            studentAnswer.setCorrectResult(StudentAnswerStatus.WRONG_ANSWER, score);
        }
        else {
            log.debug("答对判分");
            //正确
            studentAnswer.setCorrectResult(StudentAnswerStatus.RIGHT_ANSWER, score);
        }
    }

    /**
     * 批改主观题目(简答或阅读理解)
     * 
     * @param studentAnswer 习题回答
     *                       
     * @author cx
     * @since 2015/3/30
     */
    public void correctSubjective(StudentAnswer studentAnswer) {
        if (StringUtils.isEmpty(studentAnswer.getAnswerContent())) {
            log.debug("主观题未答:StringUtils.isEmpty(studentAnswer.getAnswerContent())");
            //未答；0分，待老师批阅后更新分数
            studentAnswer.setCorrectResult(StudentAnswerStatus.NOT_ANSWER, 0);
        }
        else {
            log.debug("主观题未评判");
            //主观题未评判状态；0分，待老师批阅后更新分数
            studentAnswer.setCorrectResult(StudentAnswerStatus.SUBJECTIVE_NO_VIEW, 0);
        }
    }

    /**
     * 批改阅读理解多题
     *
     * @param testExercise 作业习题
     * @param studentAnswer 习题回答
     *
     * @author cx
     * @since 2015/3/30
     */
    public void correctMulti(TestExercise testExercise, StudentAnswer studentAnswer) {
        int scoreSum = 0; //阅读理解多题总得分
        boolean isSubjective = false; //默认为非主观题
        int noAnswerCnt = 0; //子习题未答题统计

        //获取学生的子习题回答集合
        List<StudentAnswer> sonStudentAnswers = studentAnswer.getSonStudentAnswers();

        if (sonStudentAnswers == null || sonStudentAnswers.isEmpty()) {
            log.debug("子习题集合为空:sonStudentAnswers == null || sonStudentAnswers.isEmpty()");

            throw new ServiceException("子习题集合为空");
        }

        log.debug("循环子习题回答");
        for (StudentAnswer sonStudentAnswer : sonStudentAnswers) {
            sonStudentAnswer.setTestId(testExercise.getTestId());
            //递归批改子习题的答题情况
            handleStudentAnswer(sonStudentAnswer);

            scoreSum += sonStudentAnswer.getScore();

            if (!isSubjective) { //有一个子习题是主观题未评判状态时，主习题定为主观题未评判状态
                if (sonStudentAnswer.getStatus() == StudentAnswerStatus.SUBJECTIVE_NO_VIEW) {
                    log.debug("判断子习题中的主观题:sonStudentAnswer.getStatus() == StudentAnswerStatus.SUBJECTIVE_NO_VIEW");
                    isSubjective = true;
                }
                else if (sonStudentAnswer.getStatus() == StudentAnswerStatus.NOT_ANSWER) {
                    log.debug("判断子习题是否未答:sonStudentAnswer.getStatus() == StudentAnswerStatus.NOT_ANSWER");
                    noAnswerCnt++; //累加子习题未答数目
                }
            }

            sonStudentAnswer.setParentId(studentAnswer.getExerciseId()); //设定主习题的ID
        }

        if (sonStudentAnswers.size() == noAnswerCnt) {
            log.debug("阅读理解多题未答:sonStudentAnswers.size() == noAnswerCnt");

            //未答，0分
            studentAnswer.setCorrectResult(StudentAnswerStatus.NOT_ANSWER, scoreSum);
            return;
        }

        if (isSubjective) {
            log.debug("判定为主观未评判");

            //主观题未评判
            studentAnswer.setCorrectResult(StudentAnswerStatus.SUBJECTIVE_NO_VIEW, scoreSum);
            return;
        }

        if (scoreSum != testExercise.getScore()) { //子习题分数之和小于习题总分
            log.debug("答错判分:scoreSum != testExercise.getScore()");
            //错误
            studentAnswer.setCorrectResult(StudentAnswerStatus.WRONG_ANSWER, scoreSum);
        }
        else {
            log.debug("答对判分");
            //正确，满分
            studentAnswer.setCorrectResult(StudentAnswerStatus.RIGHT_ANSWER, testExercise.getScore());
        }
    }

    /**
     * 处理学生的答题信息
     *
     * @param studentAnswer 学生答题
     *
     * @author cx
     * @since 2015/3/30
     */
    public void handleStudentAnswer(StudentAnswer studentAnswer) {
        //获取作业的习题信息
        TestExercise testExercise = testService.getExerciseOfTest(studentAnswer.getTestId(), studentAnswer.getExerciseId());

        //获取习题类型
        int exerciseType = testExercise.getType();

        //习题是单选或多选
        if (exerciseType == ExerciseType.SINGLE_CHOICE || exerciseType == ExerciseType.MULTIPLE_CHOICE) {
            log.debug("选择题:exerciseType == ExerciseType.SINGLE_CHOICE || exerciseType == ExerciseType.MULTIPLE_CHOICE");
            correctChoice(testExercise, studentAnswer);
        }
        else if (exerciseType == ExerciseType.TRUE_OR_FALSE) { //习题是判断题
            log.debug("判断题:exerciseType == ExerciseType.TRUE_OR_FALSE");
            correctTrueOrFalse(testExercise, studentAnswer);
        }
        else if (exerciseType == ExerciseType.COMPLETION) { //习题是填空题
            log.debug("填空题:exerciseType == ExerciseType.COMPLETION");
            correctCompletion(testExercise, studentAnswer);
        }
        else if (exerciseType == ExerciseType.SHORT_ANSWER || exerciseType == ExerciseType.READING_COMPREHENSION) { //习题是简单题或阅读理解题
            log.debug("主观题题:exerciseType == ExerciseType.SHORT_ANSWER || exerciseType == ExerciseType.READING_COMPREHENSION");
            correctSubjective(studentAnswer);
        }
        else if (exerciseType == ExerciseType.READING_COMPREHENSION_MULTI) { //阅读理解多题
            log.debug("一题多问:exerciseType == ExerciseType.READING_COMPREHENSION_MULTI");
            correctMulti(testExercise, studentAnswer);
        }
        else {
            log.debug("不合法的习题类型");
            log.warn("不合法的习题类型:type->{}", exerciseType);
            throw new ServiceException("不合法的习题类型");
        }
    }

    /**
     * 载入选择题型的内容和学生回答
     * 
     * @param exercise 习题
     * @param studentAnswer 学生回答
     * @param showAnswer 控制加载标准答案信息
     *                 
     * @author cx
     * @since 2015/4/3
     */
    public void loadChoice(Exercise exercise, StudentAnswer studentAnswer, boolean showAnswer) {
        //获取习题选项
        List<ExerciseOption> exerciseOptions;
        if (showAnswer) {
            log.debug("获取习题选项及标准答案:overtime");
            exerciseOptions = exerciseOptionDao.getExerciseOptions(exercise.getId());
        }
        else {
            log.debug("获取习题选项");
            //不带标准答案
            exerciseOptions = exerciseOptionDao.getOptionsWithoutAnswer(exercise.getId());
        }

        if (studentAnswer != null) {
            log.debug("学生答题记录非空:studentAnswer != null");

            //获取学生的答题内容
            String answerContent = studentAnswer.getAnswerContent();
            //json转换为List
            List<Long> optionIds = new JsonUtil<>(Long.class).convertToList(answerContent);

            log.debug("循环习题选项集合");
            for (ExerciseOption exerciseOption : exerciseOptions) {
                if (optionIds.contains(exerciseOption.getId())) {
                    log.debug("答题时选择了选项:optionIds.contains(exerciseOption.getId())");
                    exerciseOption.setChoice(1);
                }
                else {
                    log.debug("答题时未选择选项");
                    exerciseOption.setChoice(0);
                }
            }
        }

        exercise.setOptions(exerciseOptions);
    }

    /**
     * 载入判断题型的内容和学生回答
     *
     * @param exercise 习题
     * @param studentAnswer 学生回答
     * @param showAnswer 控制加载标准答案信息
     *
     * @author cx
     * @since 2015/4/3
     */
    public void loadTrueOrFalse(Exercise exercise, StudentAnswer studentAnswer, boolean showAnswer) {
        long exerciseId = exercise.getId();

        //获取习题选项
        List<ExerciseOption> exerciseOptions;
        if (showAnswer) {
            log.debug("获取习题选项及标准答案:overtime");
            exerciseOptions = exerciseOptionDao.getExerciseOptions(exerciseId);
        }
        else {
            log.debug("获取习题选项");
            //不带标准答案
            exerciseOptions = exerciseOptionDao.getOptionsWithoutAnswer(exerciseId);
        }

        if (studentAnswer != null) {
            log.debug("学生答题记录非空:studentAnswer != null");

            //获取学生的答题内容
            String answerContent = studentAnswer.getAnswerContent();

            //获取习题的标准答案
            ExerciseOption exerciseOption = exerciseOptions.get(0);

            if (StringUtils.isNotEmpty(answerContent)) {
                log.debug("答题内容非空:StringUtils.isNotEmpty(answerContent)");

                exerciseOption.setChoice(Integer.valueOf(answerContent));
            }
        }

        exercise.setOptions(exerciseOptions);
    }

    /**
     * 载入填空题型的内容和学生回答
     *
     * @param exercise 习题
     * @param studentAnswer 学生回答
     * @param showAnswer 控制加载标准答案信息
     *
     * @author cx
     * @since 2015/4/3
     */
    public void loadCompletion(Exercise exercise, StudentAnswer studentAnswer, boolean showAnswer) {
        //获取填空项集合
        List<ExerciseBlank> blanks = exerciseBlankDao.getExerciseBlanks(exercise.getId());

        Map<Long, List<BlankSolution>> solutionMap = Maps.newHashMap();
        if (studentAnswer != null) {
            log.debug("学生答题非空:studentAnswer != null");

            //获取学生的答题内容,json转为List
            List<ExerciseBlank> answerBlanks = new JsonUtil<>(ExerciseBlank.class).convertToList(studentAnswer.getAnswerContent());

            log.debug("循环填空回答");
            for (ExerciseBlank answerBlank : answerBlanks) {
                solutionMap.put(answerBlank.getId(), answerBlank.getSolutions());
            }
        }

        log.debug("循环填空集合");
        for (ExerciseBlank blank : blanks) {
            //获取填空项对应的学生答题内容
            List<BlankSolution> blankSolutions = solutionMap.get(blank.getId());

            if (showAnswer) {
                log.debug("获取填空项的备选答案:overtime");

                //获取填空项的备选答案
                ExerciseBlank exerciseBlank = exerciseBlankDao.getBlankWithSolutions(blank.getId());
                blank.setSolutionTexts(exerciseBlank.getSolutionTexts());
            }
            else {
                log.debug("隐蔽答案的对错情况");

                //隐蔽每个答案的对错情况
                if (blankSolutions != null) {
                    log.debug("填空答题集合非null:blankSolutions != null");

                    for (BlankSolution blankSolution : blankSolutions) {
                        blankSolution.setRightStatus(null);
                    }
                }
            }

            blank.setSolutions(blankSolutions);
        }

        exercise.setBlanks(blanks);
    }
}
